import org.dreamwork.network.DataPacketUtil;
import org.dreamwork.secure.AlgorithmMapping;
import org.dreamwork.secure.IKeyFetcher;
import org.dreamwork.secure.SecureContext;
import org.dreamwork.secure.SecureUtil;
import org.dreamwork.util.IOUtil;
import org.dreamwork.util.StringUtil;
import org.dreamwork.util.Tools;

import java.io.*;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

/**
 * Created by seth.yang on 2016/4/28
 */
public class TunnelTest {
    public static final class CloudKeyFetcher implements IKeyFetcher {
        private PublicKey key;
        private CloudKeyFetcher () {
        }

        @Override
        public PrivateKey getPrivateKey (String issuer) throws NoSuchAlgorithmException, InvalidKeySpecException {
            return null;
        }

        @Override
        public PublicKey getPublicKey (String issuer) throws NoSuchAlgorithmException, InvalidKeySpecException {
            if (key == null) {
                String path = "D:\\workspace\\cng-sulotion\\CNG-Cloud\\modules\\cloud\\web\\WEB-INF\\keys\\cng-rsa-key.public";
                try (InputStream in = new FileInputStream (path)) {
                    byte[] buff = IOUtil.read (in);
                    X509EncodedKeySpec spec = new X509EncodedKeySpec (buff);
                    KeyFactory factory = KeyFactory.getInstance ("rsa");
                    key = factory.generatePublic (spec);
                } catch (Exception ex) {
                    throw new RuntimeException (ex);
                }
            }

            return key;
        }

        @Override
        public X509Certificate getCertificate (String issuer) throws CertificateException {
            return null;
        }
    }
    public static final SecureContext context = new SecureContext ();

    static {
        System.setProperty ("org.dreamwork.secure.provider", "org.bouncycastle.jce.provider.BouncyCastleProvider");
        context.setBlockEncryption (AlgorithmMapping.BlockEncryption.AES128_CBC);
        context.setKeyTransport (AlgorithmMapping.KeyTransport.RSA_OAEP_MGF1P);
        context.setFetcher (new CloudKeyFetcher ());
    }

    public static void main (String[] args) throws Exception {
        Socket socket = new Socket ("localhost", 8384);
        byte[] buff = new byte[34];
        buff [0] = 1;
        buff [1] = 1;
        String name = "402881e754281af10154282108a40001";
        System.arraycopy (name.getBytes (), 0, buff, 2, 32);

        SecureUtil util = new SecureUtil (context);
        Key kek = context.getFetcher ().getPublicKey (null);
        Key pubKey;

        OutputStream out = socket.getOutputStream ();
        InputStream  in  = socket.getInputStream ();

        // request a tunnel, with encryption
        DataPacketUtil.writePacket (out, buff, util, kek);

        // receive the public key
        buff = DataPacketUtil.readPacket (in, util, kek);
        buff = Tools.slice (buff, 1, buff.length - 1);
        X509EncodedKeySpec spec = new X509EncodedKeySpec (buff);
        KeyFactory factory = KeyFactory.getInstance ("RSA");
        pubKey = factory.generatePublic (spec);

        // from now on, all the transport encrypted message with the
        // received public key.
        buff = DataPacketUtil.readPacket (in, util, kek);
        if ("ready".equals (new String (buff))) {
            System.out.println ("The tunnel is ready.");
        }

        // waiting for tunnel is ready
        // ok, now open the remote fan.
        System.out.println ("opening remote fan ...");
        DataPacketUtil.writePacket (out, new byte[] {'O', 'F'}, util, pubKey);
        // read response
        buff = DataPacketUtil.readPacket (in, util, pubKey);
        if (buff [0] == 0) {
            // peer response ok.
            System.out.println ("Peer response OK");
        } else {
            System.err.println ("Peer response Fail");
        }
        Thread.sleep (3000);

        // send the quit command
        DataPacketUtil.writePacket (out, new byte[] {'Q', 0}, util, pubKey);
        System.in.read ();
    }
}